#define MSMD_C
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sched.h> 
#include <math.h>  
#include <pthread.h> 
#if defined(OS_LINUX_SOC)
#include <pwd.h>
#include <ctype.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <sys/statfs.h>  
#include <sys/resource.h>
#endif
#include "mstime.h"
#include "mstypes.h"
#include "msnetwork.h"
#include <libmslog/mslog.h>
#include "msmd.h"
#include "msstring.h"
#include "mscommon.h"
#define FLAG 		"MSMD"
/*文件格式过滤函数*/
ms_bool msmd_api_fileFormatFilter(ms_string ms_in filename)
{
//未测格式   :amr/3gp
	return (
//音视文件
		ms_urlFormat(filename, ".ts")
//音频文件
		||ms_urlFormat(filename, ".mp3")||ms_urlFormat(filename, ".flac")	
		||ms_urlFormat(filename, ".m4a")||ms_urlFormat(filename, ".wav")
		||ms_urlFormat(filename, ".wma")||ms_urlFormat(filename, ".ogg")
//视频文件
		||ms_urlFormat(filename, ".mp4")||ms_urlFormat(filename, ".flv")||ms_urlFormat(filename, ".avi")	
		||ms_urlFormat(filename, ".wmv")||ms_urlFormat(filename, ".mov")	
	);
}
 /*随机返回[val1,val2]范围内的一个无符号整形*/
ms_u32 msmd_api_randomU32(ms_u32 val1,ms_u32 val2 )
{
	ms_u32 num_srand=(ms_u32)mstime_api_upTimeUs();
	srand(num_srand) ;
	ms_u32 max=ms_max(val1, val2);
	ms_u32 min=ms_min(val1, val2);
	return (rand()% (max-min+1) + min);
} 
/*向buf的[insertOffset:len]段插入随机数据*/
ms_void msmd_api_randomInsert(ms_byte *buf,ms_s32 len,ms_s32 insertOffset)
{
	if(len<insertOffset){
		return;
	}
	int vaild_len=len-insertOffset;	//数据包前data_offset个字节不要改动,可以修改的数据长度；
	int random_len=msmd_api_randomU32(1, vaild_len);	//插入数据的长度
	int random_offset=msmd_api_randomU32(insertOffset, (len-random_len));//插入数据的位置
	int random_val=msmd_api_randomU32(0x00, 0XFF);	//插入的数据
	ms_memset(&buf[random_offset], random_val, random_len);
}
/*生成随机字符串*/
ms_void msmd_api_randomStr(ms_byte* poutBuf, ms_u32 len)
{
    ms_u32 i=0;
    ms_u08 temp=0;
    srand((ms_s32)time(0));
    for (i = 0; i < len; i++){
        temp = (ms_u08)(rand() % 256);
        if (temp == 0) {//随机数不要0
            temp = 128;
        }
        poutBuf[i] = temp;
    }
}
ms_void msmd_api_randomString(ms_byte* outStr)
{
	ms_byte outBuf[256]={0};
	ms_byte tbuf[256]={0};
	msmd_api_randomStr(outBuf, 64);
	for(int i=0;i<6;i++){
		if(ms_range(outBuf[i], 'A', 'Z')||ms_range(outBuf[i], 'a', 'z')||ms_range(outBuf[i], '0', '9')){
			ms_strcats(tbuf, outStr, "%c", outBuf[i]);
		}else{
			ms_strcats(tbuf, outStr, "%u", outBuf[i]);
		}
	}
}

ms_s32 msmd_api_read(ms_string ms_in filename,ms_pu08 ms_in buf,ms_u32 ms_in size)
{
	ms_bufcheckRetDes(-1, filename	,"Param error###filename");
	ms_bufcheckRetDes(-1, buf		,"Param error###buf");
	if(size>ms_sf(ms_f32)){
		ms_waring("Read len(%d) is out of range(0~%d),set to %d",size,ms_sf(ms_f32),ms_sf(ms_f32));
		size=ms_sf(ms_f32);
	}
	FILE *fp = fopen(filename, "r");
	if(ms_null==fp){
		ms_errRet(-1,"Open (%s) failed",filename);
	}

	ms_s32 len = fread(buf, sizeof(char), size, fp);
	if (len<0){
		fclose(fp);
		ms_errRet(-1,"Read (%s) failed",filename);
	}
	if(len<size){
		buf[len] = 0;
	}
	fclose(fp);
	return len;
}
ms_s32 msmd_api_write(ms_string ms_in filename,ms_pu08 ms_in buf,ms_u32 ms_in size,ms_string stropt)
{
	ms_bufcheckRet(-1, filename);
	ms_bufcheckRet(-1, buf);
	if(size>ms_sf(ms_f32)){
		ms_waring("Write len(%d) is out of range(0~%d),set to %d",size,ms_sf(ms_f32),ms_sf(ms_f32));	
		size=ms_sf(ms_f32);
	}
	FILE *fp = fopen(filename, stropt);
	if(ms_null==fp){
		ms_byte cmdbuf[256]={0};
		ms_cmd(cmdbuf,"touch %s ",filename);
		ms_errRet(-1,"Open (%s) failed",filename);
	}

	ms_s32 len = fwrite(buf, sizeof(char), size, fp);
	if (len<0){
		fclose(fp);
		ms_errRet(-1,"write (%s) failed",filename);
	}
	if(len<size){
		buf[len] = 0;
	}
	fclose(fp);
	return len;
}
ms_s32 msmd_api_read2(ms_string ms_in filename,ms_pu08 ms_in buf,ms_u32 ms_in size)
{
	ms_bufcheckRetDes(-1, filename	,"Param error###filename");
	ms_bufcheckRetDes(-1, buf		,"Param error###buf");
	return msmd_api_read(filename, buf,size);
}
ms_s32 msmd_api_read3(ms_string ms_in filename,ms_pu08 ms_in buf,ms_u32 ms_in size)
{
	ms_bufcheckRetDes(-1, filename	,"Param error###filename");
	ms_bufcheckRetDes(-1, buf		,"Param error###buf");
	if(size>ms_sf(ms_f32)){
		ms_waring("Read len(%d) is out of range(0~%d),set to %d",size,ms_sf(ms_f32),ms_sf(ms_f32));
		size=ms_sf(ms_f32);
	}
	FILE *fp = fopen(filename, "r");
	if(ms_null==fp){
		ms_errRet(-1,"Open (%s) failed",filename);
	}
	ms_s32 len=0;
	ms_s32 len_readtotal=0;
	ms_s32 need_read=size;
	while(len_readtotal<size){
		len= fread(&buf[len_readtotal], sizeof(char), need_read, fp);
		if(len>0){
			len_readtotal+=len;
			need_read-=len;
		}else{
			break;
		}
	}
	fclose(fp);
	return len_readtotal;
}
/*用于重要且数据量小的文件写操作，可以保护原文件不损失/坏
注意：不要用于数据量大的文件，否则会造成磁盘IO大量读写的问题*/
ms_s32 msmd_api_writeProtect(ms_string ms_in filename,ms_pu08 ms_in buf,ms_u32 ms_in size)
{
	ms_bufcheckRetDes(-1, filename	,"Param error###filename");
	ms_bufcheckRetDes(-1, buf		,"Param error###buf");
	//write_protect
	ms_byte filename_tmp[256];
	ms_sprintfs(filename_tmp, "%s_tmp", filename);
	//clear context
	ms_remove(filename_tmp);
	//write data to filename_tmp
	ms_s32 len = msmd_api_write (filename_tmp, buf,size,"w");
	if (len>0){
		//copy filename_tmp to filename
		ms_byte cmdbuf[512]={0};
		ms_snprints(cmdbuf,"cp  -fr    %s  %s",filename_tmp,filename);
		if(ms_false==ms_cmdRet(cmdbuf)){
			ms_errRet(-1,"inner error:cmd [%s] failed",cmdbuf);			
		}
		ms_cmd(cmdbuf,"rm  -fr   %s   ",filename_tmp);
	}
	return len;
}
ms_s32 msmd_api_writea(ms_string ms_in filename,ms_pu08 ms_in buf,ms_u32 ms_in size)
{
	ms_bufcheckRetDes(-1, filename	,"Param error###filename");
	ms_bufcheckRetDes(-1, buf		,"Param error###buf");
	return  msmd_api_write (filename, buf,size,"a+");
}
ms_s64 msmd_api_getFileSize(ms_string ms_in filename)
{
	struct stat filebuf;
	ms_byte filetmp[1024]={0};
	if(ms_strncmp_seq(filename, "file://")){
		ms_memcpy(filetmp, &filename[ms_buflen("file://")], (ms_buflen(filename)-ms_buflen("file://")+1))
	}else{
		ms_strcpy(filetmp, filename);
	}
	if(stat(filetmp,&filebuf)<0){
		ms_errRet(0, "stat %s failed(%d,%s)", filetmp, errno, strerror(errno));
	}
	return filebuf.st_size;
}	
ms_bool msmd_api_newMsgFile(ms_string ms_in filename)
{
	if(msmd_api_getFileSize(filename)>(10*ms_MB)){ 
		ms_byte cmdline[256]={0}; 
		ms_s08 strCurDTime[64]={0};
		ms_cmd(cmdline, "  mv  %s  %s_%s.txt", filename,filename,mstime_api_curDTime(mstime_fmt_datetime_ex3,strCurDTime)); 
	}
	return ms_true;
}
ms_s08 msmd_api_changeUser(ms_string ms_in username)
{
	ms_bufcheckRetDes(-1, username	,"Param error###username");
#if defined(OS_LINUX_SOC)
	struct passwd *pw=getpwnam(username);
	if ( ms_null==pw ){
    		ms_errRet(-1, "ERROR: can't find user '%s': getpwnam failed", username);
	}

	if (setgid(pw->pw_gid) < 0){
		ms_errRet(-2, "ERROR: can't change group id: setgid");
	}
  	if (setuid(pw->pw_uid) < 0){
    		ms_errRet(-3, "ERROR: can't change user id: setuid");
  	}
  	ms_info("Changed process user id to '%s'", username);
#else
	ms_funcNosupports;
#endif
	return  0;
}
ms_s32 msmd_api_getCpuNum(ms_void)
{
 	 static ms_s32 cpunum=0;
	 if(cpunum>0){
		return cpunum;
	 }
#if defined (_SC_NPROCESSORS_CONF)
  	cpunum= (ms_s32) sysconf(_SC_NPROCESSORS_CONF);
#elif defined (_SC_NPROCESSORS_ONLN)
  	cpunum= (ms_s32) sysconf(_SC_NPROCESSORS_ONLN);
#elif defined (_SC_NPROC_ONLN)
  	cpunum= (ms_s32) sysconf(_SC_NPROC_ONLN);
#elif defined (HPUX)
	#include <sys/mpctl.h>
	cpunum = mpctl(MPC_GETNUMSPUS, 0, 0);
#else
	cpunum = 0;
	errno = ENOSYS;
#endif
	if(cpunum>mscfg_maxnum_cpu){
		ms_fix("Oh my god,what? cpu_num > %d ???,set to default %d",mscfg_maxnum_cpu,mscfg_maxnum_cpu);
		cpunum=mscfg_maxnum_cpu;
	}

//检查CPU数值是否获取正确
	ms_s32 cpunum_index=0;
	ms_byte cmdline[256]={0};
	ms_sprintfs(cmdline, "cat /proc/stat | grep cpu%d", cpunum);
	if(ms_false==ms_cmdRet(cmdline)){	//CPU数值获取错误
		ms_s32 cpunum_pre=cpunum;
		for(cpunum_index=0;cpunum_index<mscfg_maxnum_cpu;cpunum_index++){
			ms_sprintfs(cmdline, "cat /proc/stat | grep cpu%d", cpunum_index);
			if(ms_false==ms_cmdRet(cmdline)){
				break;
			}else{
				cpunum=cpunum_index+1;
			}
		}
		if(cpunum!=cpunum_pre){
			ms_byte msg[512]={0};
			ms_logfileMsg(FILE_LOG_WARING,msg, "Cpu num change from %d to %d",cpunum_pre,cpunum);
			ms_waring("%s", msg);
		}
	}
	return cpunum;
}

ms_void msmd_api_clearCache( MEMCLEARLevel  ms_in memclear_level)
{
#if defined(OS_LINUX_SOC)
	ms_u08 memclear_cmd[64]={0};
	ms_cmd(memclear_cmd,"echo %d  >  /proc/sys/vm/drop_caches",memclear_level);
#else
	ms_funcNosupports;
#endif
}
/*清除系统日志*/
ms_void msmd_api_clearSysLog( ms_void)
{
#if defined(OS_LINUX_SOC)
	char logclear_cmd[64]={0};
	ms_cmd(logclear_cmd,"%s","rm -fr  /var/log/syslog.*     ");
	ms_cmd(logclear_cmd,"%s","rm -fr  /var/log/*.log.*");
	ms_cmd(logclear_cmd,"%s","rm -fr  /var/log/*.log");
	ms_cmd(logclear_cmd,"%s","rm -fr  /var/log/*.err.*");
#else
	ms_funcNosupports;
#endif
}
/*清除应用程序日志*/
ms_void msmd_api_clearAppLog( ms_void)
{
#if defined(OS_LINUX_SOC)
	char logclear_cmd[64]={0};
	ms_cmd(logclear_cmd,"rm -fr  %s/*",PATH_LOG_MSCORE);
	ms_cmd(logclear_cmd,"rm -fr  %s/*.log",PATH_LOG_MSSRS);
	ms_cmd(logclear_cmd,"rm -fr  %s/*.log",PATH_LOG_MSNGINX);
	ms_cmd(logclear_cmd,"rm -fr  %s/*.log",PATH_LOG_MSTOMCAT);
#else
	ms_funcNosupports;
#endif
}
/*清除内核升级文件*/
ms_void msmd_api_cleanKernelUpgradeFile( ms_void)
{
#if defined(OS_LINUX_SOC)
	char logclear_cmd[64]={0};
	ms_cmd(logclear_cmd,"%s","apt -y autoremove");
#else
	ms_funcNosupports;
#endif
}

ms_bool msmd_api_isFileExsit(ms_string ms_in filename)
{
	ms_bufcheckRetDes(ms_false, filename	,"Param error###filename");
	return (ms_access(filename,F_OK) < 0) ? ms_false : ms_true;
}
ms_bool msmd_api_isInstall(ms_string name)
{
	ms_byte path[256]={0};
	ms_sprintfs(path, "/usr/share/doc/%s", name);
	return  (ms_access(path,F_OK) < 0) ? ms_false : ms_true;
}
ms_bool msmd_api_isInstallByBin(ms_string binname)
{
#define findpath(path,path_pre)  \
	ms_sprintfs(path, "%s/%s", path_pre,binname); \
	if  (!(ms_access(path,F_OK) < 0)) { \
		return ms_true; \
	} 
	ms_byte path[256]={0};
	findpath(path,"/bin");
	findpath(path,"/usr/bin");
	findpath(path,"/usr/local/bin");
	findpath(path,"/sbin");
	findpath(path,"/usr/sbin");
	findpath(path,"/usr/local/sbin");

	ms_warRet(ms_false, "No install %s", binname);
}
DECENCMode   msmd_api_getDecEncMode(ms_void)  
{  
	DECENCMode decode_mode=decencmode_sw;
	char info[1024]={0};
	if((ms_true==msmd_api_isInstall("inxi")) && (ms_cmdRead("inxi -SG | grep NVIDIA", info, sizeof(info))>0)){
		decode_mode=decencmode_nvidia;
		ms_verbose("Use hwaccel cuvid(nvidia)");
	}else{
		decode_mode=decencmode_sw;
		ms_verbose("Use sw decoder and encoder");
	}
	return decode_mode;
}
ms_void msmd_api_setCpuFreq(ms_void)
{
	//查看当前CPU频率：cat /proc/cpuinfo | grep "cpu MHz"
	if(ms_true==msmd_api_isFileExsit("/sys/bus/cpu/drivers/processor/cpu0/cpufreq/scaling_governor")){
		//查看支持的CPU运行模式：/sys/bus/cpu/drivers/processor/cpu3/cpufreq/scaling_available_governors 
		ms_s32 cpuNum=msmd_api_getCpuNum();
		if(cpuNum>0){
			ms_byte cmdbuf[256]={0};
			for(ms_s32 index=0;index<cpuNum;index++){
				ms_cmd(cmdbuf,"echo performance > /sys/bus/cpu/drivers/processor/cpu%d/cpufreq/scaling_governor",index);
			}
		}
	}
#if 0	
	else if(ms_true==msmd_api_isInstall("cpufrequtils")){
		//ms_system("cpufreq-info");
		//cpufreq-set -g   {powersave, userspace, ondemand, conservative, performance}
		ms_s32 cpuNum=msmd_api_getCpuNum();
		if(cpuNum>0){
			ms_byte cmdbuf[256]={0};
			for(ms_s32 index=0;index<cpuNum;index++){
				ms_cmd(cmdbuf,"cpufreq-set -c %d -g  performance",index);
			}
		}
	}
#endif
}
ms_void msmd_api_taskSched(unsigned long pid,int cup_start,int cup_end)  
{
	if(cup_start<0
		||cup_start>cup_end){
		ms_warNoret("msched_api_taskSet no need--pid:%ld,cup_start, cup_end:%d-%d,enter auto mode", pid,cup_start, cup_end);
	}
	cpu_set_t mask;  
	cpu_set_t get;
	CPU_ZERO(&mask);  
		
	ms_s32 cpu_index=0;
	for(cpu_index=cup_start;ms_noMore(cpu_index, cup_end);cpu_index++){
		CPU_SET(cpu_index, &mask);	
	}
	if (sched_setaffinity(pid, sizeof(mask), &mask) < 0) {	
		ms_error("set thread affinity failed");  
	}  
}
static ms_s08 msmd_api_setRlimit(ms_s32 resource,ms_string resource_name)
{
	struct rlimit rlim_file;
	if(0!= getrlimit(resource, (struct rlimit *)&rlim_file)){
		ms_errRet(-1,"getrlimit %s error",resource_name);
	}
	ms_debug("set  %s from (%d) to max(%d)",resource_name,(int)rlim_file.rlim_cur ,(int)rlim_file.rlim_max);
	rlim_file.rlim_cur=rlim_file.rlim_max;
	if(0!=setrlimit(resource, (const struct rlimit *)&rlim_file) ){
		ms_errRet(-1,"setrlimit %s error",resource_name);
	}
//max_user_watches
	if(RLIMIT_NOFILE==resource){
		ms_byte cmdbuf[256]={0};
		ms_cmd(cmdbuf, "echo %d >  /proc/sys/fs/inotify/max_user_watches", (int)rlim_file.rlim_max);
	}
}
ms_s08 msmd_api_setUlimit(ms_void)
{
//max_open_file
	msmd_api_setRlimit(RLIMIT_NOFILE,"max_open_file");
//max_stack
	//msmd_api_setRlimit(RLIMIT_STACK,"max_stack");
}
ms_void msmd_api_pstree(ms_string pos_version,ms_u32 pid,ms_string strout)
{
	if(ms_true==msmd_api_isInstallByBin("pstree")){
		if(ms_true==msstr_api_isCasestr(pos_version, "Ubuntu 16.04")){
			ms_sprintfs(strout, "pstree -p %d -n -A", pid);
		}else{
			ms_sprintfs(strout, "pstree -p %d -n -A  -t", pid);
		}
	}
}
ms_bool msmd_api_checkVarTypeLen(ms_string obuf,ms_string exInfo)
{
	ms_bool ret_check=ms_true;
	//mslog_api_init( mslog_level_more|mslog_enable_stdprint|mslog_enable_linefunc, ms_null,ms_null, ms_null);
	char ret_char=-1;
	short ret_short=-1;
	int ret_int=-1;
	int64_t ret_64=-1;
	long ret_long=-1;
	ms_byte tbuf[256]={0};
	if(ms_null!=obuf){
		ms_strcats(tbuf, obuf, "char(-1)=%d;",ret_char);
		ms_strcats(tbuf, obuf, "short(-1)=%d;",ret_short);
		ms_strcats(tbuf, obuf, "int(-1)=%d;",ret_int);
		ms_strcats(tbuf, obuf, "long(-1)=%d;",ret_long);
		ms_strcats(tbuf, obuf, "int64_t(-1)=%s;",ms_num2str(ret_64));
		ms_strcats(tbuf, obuf, "size(char)=%d;",ms_bufsize(char));
		ms_strcats(tbuf, obuf, "size(short)=%d;",ms_bufsize(short));
		ms_strcats(tbuf, obuf, "size(int)=%d;",ms_bufsize(int));
		ms_strcats(tbuf, obuf, "size(long)=%d;",ms_bufsize(long));
		ms_strcats(tbuf, obuf, "size(int64_t)=%d",ms_bufsize(int64_t));
	}
	if(-1!=ret_char){
		ms_strcats(tbuf, exInfo, "char(-1)=%d;",ret_char);ms_waring("%s",tbuf);
		ret_check=ms_false;
	}
	if(-1!=ret_short){
		ms_strcats(tbuf, exInfo, "short(-1)=%d;",ret_short);ms_waring("%s",tbuf);
		ret_check=ms_false;
	}
	if(-1!=ret_int){
		ms_strcats(tbuf, exInfo, "int(-1)=%d;",ret_int);ms_waring("%s",tbuf);
		ret_check=ms_false;
	}
	if(-1!=ret_long){
		ms_strcats(tbuf, exInfo, "long(-1)=%d;",ret_long);ms_waring("%s",tbuf);
		ret_check=ms_false;
	}
	if(-1!=ret_64){
		ms_strcats(tbuf, exInfo, "int64_t(-1)=%s;",ms_num2str(ret_64));ms_waring("%s",tbuf);
		ret_check=ms_false;
	}
	if(1!=ms_bufsize(char)){
		ms_strcats(tbuf, exInfo, "size(char)=%d;",ms_bufsize(char));ms_waring("%s",tbuf);
		ret_check=ms_false;
	}
	if(2!=ms_bufsize(short)){
		ms_strcats(tbuf, exInfo, "size(short)=%d;",ms_bufsize(short));ms_waring("%s",tbuf);
		ret_check=ms_false;
	}
	if(4!=ms_bufsize(int)){
		ms_strcats(tbuf, exInfo, "size(int)=%d;",ms_bufsize(int));ms_waring("%s",tbuf);
		ret_check=ms_false;
	}
	if(8!=ms_bufsize(ret_long)){
		ms_strcats(tbuf, exInfo, "size(long)=%d;",ms_bufsize(long));ms_waring("%s",tbuf);
		ret_check=ms_false;
	}
	if(8!=ms_bufsize(int64_t)){
		ms_strcats(tbuf, exInfo, "size(int64_t)=%d",ms_bufsize(int64_t));ms_waring("%s",tbuf);
		ret_check=ms_false;
	}
	return ret_check;
}
ms_bool msmd_api_timeToSave(ms_u64 *prequest_intime)
{
	if(mstime_api_counterAsyncUs(prequest_intime, ms_usminutes(1))){
		return ms_true;
	}else{
		return ms_false;
	}
}
ms_void msmd_api_watchdog(ms_s32 (*childfunc)(ms_pvoid ),ms_pvoid ms_in arg)
{
	ms_pamcheck(childfunc, "childfunc");
	//mssignal_api_catch();
	pid_t fpid=-1;
fork_pid:	
	fpid=fork();   
	if (fpid < 0) { 
		ms_errExit(1,"error in fork!");   
	}else if (fpid == 0) {  //child process
		childfunc(arg);
	}else{  
		ms_verbose("I am father");
		pid_t pid;
		ms_s32 status;
		while(1){
			pid = waitpid(0,&status,WNOHANG);
			if(pid>0){
				if(mswait_ifexited(status)){
					ms_info("child[%d] has exited",pid);
				}else if(mswait_ifsignaled(status)){
					ms_info("child[%d] is end by signal:%s",pid,mssignal_desstring[(int)mswait_termsig(status)]);
				}
				goto fork_pid;
			}else if(pid==0){
			
			}else{
				if(10!=errno){
					ms_error("wait:  %d %s",errno, strerror(errno));
				}
			}
			ms_sleep(1);
		}
	}  
}
ms_void msmd_api_startDaemon(ms_string ms_in logdir)
{
	ms_pamcheck(logdir, "logdir");
	pid_t pid= fork();
	/* Start forking */
	if (pid < 0){
		ms_errExit(-1, "ERROR: fork");
  	}else if (pid > 0){
		ms_exit(0); 
	}
	/* First child process */
	setsid();  /* become session leader */
	if ((pid = fork()) < 0){
		ms_errExit(-1, "ERROR: fork");
	}else if (pid > 0){                /* first child */
		ms_exit(0);
	}
	umask(022);
	ms_u08 i=0;
	for(i=0;i<3;i++){
		close(i);
	}
	if (chdir(logdir) < 0){
		ms_errExit(-1, "ERROR: can't change directory to %s: chdir", logdir);
	}
}

/*
optstring中的指定的内容的意义（例如getopt(argc, argv, "ab:c:de::");）
  1.单个字符：如“a”，表示选项没有参数，使用时"-a"
  2.单个字符后接一个冒号：如“b:c:”，表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开，使用时"-b test"；
  3.单个字符后跟两个冒号：如“e::”，表示该选项后可以跟一个参数，也可以不跟。如果参数，参数必须紧跟在选项后不能以空格隔开，使用时"-etest"或"-e"；

	printf("option=c, optopt=%c, optarg=%s\n", optopt, optarg);
	printf("argv[%d]=%s\n", optind, argv[optind]);

*/
ms_void msmd_api_parseOpt(int argc, char **argv,ms_string optstring,MDOPTList *pmdoptList,ms_s32 optListNum)
{
    int result;
    //opterr = 0;  //使getopt不行stderr输出错误信息
 	ms_s32 optListIndex=0;
    while( (result = getopt(argc, argv, optstring)) != -1 ){
		printf("result =%c,\n", result);
		for(optListIndex=0;optListIndex<optListNum;optListIndex++){
			if(result==pmdoptList[optListIndex].opt){
				printf("optopt=%c, optarg=%s\n", result,optopt, optarg);
				pmdoptList[optListIndex].optFunc(pmdoptList[optListIndex].optFuncArg,optarg);
				break;
			}
		}	
    }
}
/*******************************************************************************
 * 功能: ascii编码为base64格式
 ******************************************************************************/
ms_s32 msmd_api_ascii2Base64(const ms_byte * ms_in base64Char,const ms_u08* ms_in pchar, ms_s32 ms_in len_char, ms_byte* ms_out pbase64)
{
    ms_s32 i, len_base64;
    ms_u08 current;
    for (i = 0, len_base64 = 0; i < len_char; i += 3){
        current = (pchar[i] >> 2);
        current &= (ms_u08)0x3F;
        pbase64[len_base64++] = base64Char[(ms_s32)current];
        current = ((ms_u08)(pchar[i] << 4)) & ((ms_u08)0x30);
        if (i + 1 >= len_char){
            pbase64[len_base64++] = base64Char[(ms_s32)current];
            pbase64[len_base64++] = '=';
            pbase64[len_base64++] = '=';
            break;
        }
        current |= ((ms_u08)(pchar[i + 1] >> 4)) & ((ms_u08)0x0F);
        pbase64[len_base64++] = base64Char[(ms_s32)current];
        current = ((ms_u08)(pchar[i + 1] << 2)) & ((ms_u08)0x3C);
        if (i + 2 >= len_char){
            pbase64[len_base64++] = base64Char[(ms_s32)current];
            pbase64[len_base64++] = '=';
            break;
        }
        current |= ((ms_u08)(pchar[i + 2] >> 6)) & ((ms_u08)0x03);
        pbase64[len_base64++] = base64Char[(ms_s32)current];
        current = ((ms_u08)pchar[i + 2]) & ((ms_u08)0x3F);
        pbase64[len_base64++] = base64Char[(ms_s32)current];
    }
    pbase64[len_base64] = '\0';
    return len_base64;
}
/*******************************************************************************
 * 功能: base64格式解码为ascii
 ******************************************************************************/
ms_s32 msmd_api_base642Ascii(const ms_byte * ms_in base64Char,const char* ms_in pbase64, ms_u08* ms_out pchar)
{
    ms_s32 i, len_char;
    ms_u08 k;
    ms_u08 temp[4];
    for (i = 0, len_char = 0; pbase64[i] != '\0'; i += 4){
        memset(temp, 0xFF, sizeof(temp));
        for (k = 0; k < 64; k++){
            if (base64Char[k] == pbase64[i])
                temp[0] = k;
        }
        for (k = 0; k < 64; k++){
            if (base64Char[k] == pbase64[i + 1]){
                temp[1] = k;
            }
        }
        for (k = 0; k < 64; k++){
            if (base64Char[k] == pbase64[i + 2]){
                temp[2] = k;
            }
        }
        for (k = 0; k < 64; k++){
            if (base64Char[k] == pbase64[i + 3]){
                temp[3] = k;
            }
        }
        pchar[len_char++] = ((ms_u08)(((ms_u08)(temp[0] << 2)) & 0xFC)) |
                       ((ms_u08)((ms_u08)(temp[1] >> 4) & 0x03));
        if (pbase64[i + 2] == '='){
            break;
        }
        pchar[len_char++] = ((ms_u08)(((ms_u08)(temp[1] << 4)) & 0xF0)) |
                       ((ms_u08)((ms_u08)(temp[2] >> 2) & 0x0F));
        if (pbase64[i + 3] == '='){
            break;
        }
        pchar[len_char++] = ((ms_u08)(((ms_u08)(temp[2] << 6)) & 0xF0)) |
                       ((ms_u08)(temp[3] & 0x3F));
    }
    return len_char;
}

ms_string msmd_api_getFileType(ms_string filename)
{
	struct stat buf;
	if(lstat(filename,&buf)<0){
		ms_errRet("error","lstat %s error",filename);
	}
	if(S_ISREG(buf.st_mode)){
		return "regular";
	}else if(S_ISDIR(buf.st_mode)){
		return "diretory";
	}else if(S_ISBLK(buf.st_mode)){
		return "block special";
	}else if(S_ISCHR(buf.st_mode)){
		return "character special";
	}else if(S_ISFIFO(buf.st_mode)){
		return "fifo";
	}else if(S_ISLNK(buf.st_mode)){
		return  "symbolic link";
	}else if(S_ISSOCK(buf.st_mode)){
		return "socket";
	}else{
		return "unknown";
	}
}

ms_bool msmd_api_isConflictLib(ms_string libname,ms_string main_ver,ms_string version)
{
	ms_byte libpath1[1024]={0};
	ms_byte libpath2[1024]={0};
	ms_byte libpath3[1024]={0};
	ms_byte full_ver[1024]={0};
	if((ms_null==main_ver)||(ms_null==version)){
		ms_string pstrVer=(ms_null==main_ver) ? version : main_ver;
		ms_sprintfs(full_ver, "%s.so.%s",libname,version)
	}else{
		ms_sprintfs(full_ver, "%s-%s.so.%s",libname,main_ver,version)
	}
	ms_sprintfs(libpath1, "/usr/lib/x86_64-linux-gnu/%s", full_ver);
	ms_sprintfs(libpath2, "/lib/x86_64-linux-gnu/%s", full_ver);
	ms_sprintfs(libpath3, "/usr/local/lib/%s", full_ver);
	if( (ms_access(libpath1,F_OK) < 0)
		&&(ms_access(libpath2,F_OK) < 0)
		&&(ms_access(libpath3,F_OK) < 0)
	){
		return ms_false;
	}else{
		return ms_true;
	}

}
#undef MSMD_C
